﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO.Ports;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Windows;
using System.Windows.Threading;
using AutoMapper;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using HandyControl.Controls;
using HandyControl.Data;
using ModbusLib;
using ModbusLib.Base;
using ProtocalLib.Base;
using 多协议通信平台.Base;
using 多协议通信平台.Common;
using 多协议通信平台.Entity;
using 多协议通信平台.Models;

namespace 多协议通信平台.ViewModels.Protocal
{
    public partial class ModbusViewModel : BaseViewModel
    {
        private System.Timers.Timer timer;
        private ModbusMaster master;
        public ModbusViewModel()
        {
            PageTitle = "Modbus";
            InitDic();

            timer = new System.Timers.Timer();
            timer.Interval = IntervalMs;
            timer.AutoReset = true;
            timer.Elapsed += Timer_Elapsed;

            InitSimulatePoints();
        }

        [ObservableProperty]
        private string communicationType = "串口";

        [ObservableProperty]
        private string iP;

        [ObservableProperty]
        private int port;

        [ObservableProperty]
        private int recvTimeout = 5000;

        [ObservableProperty]
        private string transmissionMode = "RTU";

        [ObservableProperty]
        private int slaveId;

        [ObservableProperty]
        private string portName;

        [ObservableProperty]
        private int baudRate = 9600;

        [ObservableProperty]
        private int dataBit = 8;

        [ObservableProperty]
        private Parity parity = Parity.None;

        [ObservableProperty]
        private StopBits stopBit = StopBits.One;

        [ObservableProperty]
        private string connectionStatus = "未连接";

        private int intervalMs = 1000;
        public int IntervalMs
        {
            get { return intervalMs; }
            set
            {
                if (value < 0) return;
                if (intervalMs == value) return;
                SetProperty(ref intervalMs, value);
                if (timer != null)
                    timer.Interval = value;
            }
        }

        [ObservableProperty]
        private ModbusPoint selectedPoint;

        [ObservableProperty]
        private bool dialogVisible = false;

        [ObservableProperty]
        private string purpose = "Add";

        [ObservableProperty]
        private bool comStatus = false;

        public Dictionary<string, EndianType> ByteOrders { get; set; } = new Dictionary<string, EndianType>();
        public ObservableCollection<ModbusPoint> ModbusPoints { get; set; } = new ObservableCollection<ModbusPoint>();
        public ObservableCollection<Data_ModbusLog> ModbusLogList { get; set; } = new ObservableCollection<Data_ModbusLog>();

        private void InitSimulatePoints()
        {
            // 3,5,7,8  16,18,19,20,21,23
            // InputRegister
            ModbusPoints.Add(new ModbusPoint() { NodeID = 1, SlaveId = 1, DataType = "Int16", Address = "30003" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 2, SlaveId = 1, DataType = "Int16", Address = "30005" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 3, SlaveId = 1, DataType = "Int16", Address = "30007" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 4, SlaveId = 1, DataType = "Int16", Address = "30008" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 5, SlaveId = 1, DataType = "Single", Address = "30013" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 6, SlaveId = 1, DataType = "Single", Address = "30015" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 7, SlaveId = 1, DataType = "Single", Address = "30017" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 8, SlaveId = 1, DataType = "Int16", Address = "30020" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 9, SlaveId = 1, DataType = "Int16", Address = "30021" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 10, SlaveId = 1, DataType = "Int16", Address = "30023" });

            // CoilStatus
            ModbusPoints.Add(new ModbusPoint() { NodeID = 11, SlaveId = 1, DataType = "bool", Address = "00003" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 12, SlaveId = 1, DataType = "bool", Address = "00005" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 13, SlaveId = 1, DataType = "bool", Address = "00007" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 14, SlaveId = 1, DataType = "bool", Address = "00008" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 15, SlaveId = 1, DataType = "bool", Address = "00016" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 16, SlaveId = 1, DataType = "bool", Address = "00018" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 17, SlaveId = 1, DataType = "bool", Address = "00019" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 18, SlaveId = 1, DataType = "bool", Address = "00020" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 19, SlaveId = 1, DataType = "bool", Address = "00021" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 20, SlaveId = 1, DataType = "bool", Address = "00023" });

            // InputCoil
            ModbusPoints.Add(new ModbusPoint() { NodeID = 21, SlaveId = 1, DataType = "bool", Address = "10003" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 22, SlaveId = 1, DataType = "bool", Address = "10005" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 23, SlaveId = 1, DataType = "bool", Address = "10007" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 24, SlaveId = 1, DataType = "bool", Address = "10008" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 25, SlaveId = 1, DataType = "bool", Address = "10016" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 26, SlaveId = 1, DataType = "bool", Address = "10018" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 27, SlaveId = 1, DataType = "bool", Address = "10019" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 28, SlaveId = 1, DataType = "bool", Address = "10020" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 29, SlaveId = 1, DataType = "bool", Address = "10021" });
            ModbusPoints.Add(new ModbusPoint() { NodeID = 30, SlaveId = 1, DataType = "bool", Address = "10023" });

            
            ModbusPoints.Clear();
            IService.IBaseService baseService = IocHelper.GetService();
            List<Data_ModbusPoint> data_ModbusPoints = baseService.SelectList<Data_ModbusPoint>(null);
            List<ModbusPoint> modbusPoints = MapperHelper.MapToList<ModbusPoint>(data_ModbusPoints);
            modbusPoints.ForEach(m => ModbusPoints.Add(m));

            // LogList
            return;
            ModbusLogList.Add(new Data_ModbusLog() { SlaveId = 1, ComPort = "COM2", Status = 0, MsgType = "Send", Content = "0x01 0x02 0x03 0x04" });
            ModbusLogList.Add(new Data_ModbusLog() { SlaveId = 1, ComPort = "COM2", Status = 0, MsgType = "Recv", Content = "0x01 0x02 0x03 0x04" });
            ModbusLogList.Add(new Data_ModbusLog() { SlaveId = 1, ComPort = "COM2", Status = 0, MsgType = "Send", Content = "0x01 0x02 0x03 0x04" });
            ModbusLogList.Add(new Data_ModbusLog() { SlaveId = 1, ComPort = "COM2", Status = 1, MsgType = "Recv", Content = "0x01 0x02 0x03 0x04" });
        }

        [RelayCommand]
        public void ConnectModbus()
        {
            try
            {
                if(CommunicationType == "SerialPort")
                {
                    if(TransmissionMode == "RTU")
                    {
                        master = new ModbusRTU(PortName, BaudRate, Parity, DataBit, StopBit);
                        master.Connect();
                        ConnectionStatus = "已连接";
                        ComStatus = true;
                    }
                    else if(TransmissionMode == "ASCII")
                    {
                        master = new ModbusASCII(PortName, BaudRate, Parity, DataBit, StopBit);
                        master.Connect();
                        ConnectionStatus = "已连接";
                        ComStatus = true;
                    }
                }
                else if(CommunicationType == "Network")
                {
                    master = new ModbusTCP(IP, Port, RecvTimeout);
                    master.Connect();
                    ConnectionStatus = "已连接";
                    ComStatus = true;
                }
            }
            catch (Exception ex)
            {
                ConnectionStatus = ex.Message;
                Growl.Error(new GrowlInfo()
                {
                    Message = ex.Message,
                    ShowCloseButton = true,
                    WaitTime = 2
                });
            }
        }

        [RelayCommand]
        public void DisConnectModbus()
        {
            try
            {
                if (master != null)
                    master.Disconnect();
                ConnectionStatus = "断开连接";
                ComStatus = false;
            }
            catch (Exception ex)
            {
                connectionStatus = ex.Message;
                Growl.Error(new GrowlInfo()
                {
                    Message = ex.Message,
                    ShowCloseButton = true,
                    WaitTime = 2
                });
            }
        }

        [RelayCommand]
        public void StartMonitor()
        {
            GrowlInfo growlInfo = CheckConnectStatus();
            if(growlInfo.Type == InfoType.Error)
            {
                Growl.Error(growlInfo);
                return;
            }

            timer.Start();
            //ReadAndSet();
        }

        private GrowlInfo CheckConnectStatus()
        {
            if (master == null)
            {
                return new GrowlInfo()
                {
                    Message = "Modbus对象未初始化",
                    ShowCloseButton = true,
                    WaitTime = 2,
                    Type = InfoType.Error
                };
            }
            if (master is ModbusRTU modbusRTU)
            {
                if (!modbusRTU.Connected)
                {
                    return new GrowlInfo()
                    {
                        Message = "串口对象未打开",
                        ShowCloseButton = true,
                        WaitTime = 2,
                        Type = InfoType.Error
                    };
                }
            }
            else if (master is ModbusASCII modbusASCII)
            {
                if (!modbusASCII.Connected)
                {
                    return new GrowlInfo()
                    {
                        Message = "串口对象未打开",
                        ShowCloseButton = true,
                        WaitTime = 2,
                        Type = InfoType.Error
                    };
                }
            }
            else if (master is ModbusTCP modbusTCP)
            {
                if (!modbusTCP.Connected)
                {
                    return new GrowlInfo()
                    {
                        Message = "网口未打开",
                        ShowCloseButton = true,
                        WaitTime = 2,
                        Type = InfoType.Error
                    };
                }
            }
            return new GrowlInfo()
            {
                Type = InfoType.Success
            };
        }

        [RelayCommand]
        public void StopMonitor()
        {
            timer.Stop();
        }

        [RelayCommand]
        public void AddModbusPoint()
        {
            Purpose = "Add";
            SelectedPoint = new ModbusPoint();
            DialogVisible = true;
        }

        [RelayCommand]
        public void ShowWriteDialog(object obj)
        {
            Purpose = "Write";
            DialogVisible = true;
        }

        [RelayCommand]
        public void EditPointSet(ModbusPoint model)
        {
            Purpose = "Edit";
            SelectedPoint = CommonHelper.DeepCopy<ModbusPoint>(model);
            DialogVisible = true;
        }

        [RelayCommand]
        public void DeletePointSet(ModbusPoint model)
        {
            ModbusPoints.Remove(model);
        }

        [RelayCommand]
        public void SaveSet(ModbusPoint model)
        {
            if (model.NodeID == 0)
            {
                model.NodeID = ModbusPoints.Count + 1;
                ModbusPoints.Add(model);
            }
            else
            {
                ModbusPoint? ModbusPoint = ModbusPoints.FirstOrDefault(m => m.NodeID == model.NodeID);
                if (ModbusPoint != null)
                {
                    PropertyHelper.CopyProperties(model, ModbusPoint);
                }
            }
        }

        private void InitDic()
        {
            foreach (var val in Enum.GetValues<EndianType>())
            {
                string? name = Enum.GetName<EndianType>(val);
                ByteOrders.Add(name, val);
            }
        }

        int errorCount = 0;

        private void Timer_Elapsed(object? sender, ElapsedEventArgs e)
        {
            if (errorCount > 3)
            {
                timer.Stop();
                errorCount = 0;
                return;
            }

            if (master == null)
            {
                Growl.Error(new GrowlInfo()
                {
                    Message = "Modbus对象未初始化",
                    ShowCloseButton = true,
                    WaitTime = 2
                });
                errorCount++;
                return;
            }
            GrowlInfo growlInfo = CheckConnectStatus();
            if (growlInfo.Type == InfoType.Error)
            {
                Growl.Error(growlInfo);
                errorCount++;
                return;
            }
            int count = ModbusPoints.Count;
            if (count == 0) return;
            ReadAndSet();
        }

        /// <summary>
        /// 分批读取并将数据加载到页面上
        /// </summary>
        private void ReadAndSet()
        {
            int count = ModbusPoints.Count;
            if (count > 8)
            {
                //优化，范围查询
                //ModbusPoints
                List<ModbusPoint> CoilStatusList = new List<ModbusPoint>();
                List<ModbusPoint> InputCoilList = new List<ModbusPoint>();
                List<ModbusPoint> InputRegisterList = new List<ModbusPoint>();
                List<ModbusPoint> HoldRegisterList = new List<ModbusPoint>();

                for (int i = 0; i < ModbusPoints.Count; i++)
                {
                    switch (ModbusPoints[i].Region)
                    {
                        case FunctionType.RCoilStatus:
                            CoilStatusList.Add(ModbusPoints[i]);
                            break;
                        case FunctionType.RInputCoil:
                            InputCoilList.Add(ModbusPoints[i]);
                            break;
                        case FunctionType.RHoldingRegister:
                            InputRegisterList.Add(ModbusPoints[i]);
                            break;
                        case FunctionType.RInputRegister:
                            HoldRegisterList.Add(ModbusPoints[i]);
                            break;
                        default:
                            break;
                    }
                }


                // 单个类型 点位数大于 8，采用范围查询；小于 8，依旧单个点位查询
                if (CoilStatusList.Count > 8)
                {
                    //OptimizedMap
                    OptimizeHandle<bool>(CoilStatusList, FunctionType.RCoilStatus);
                }
                else
                {
                    foreach (var item in CoilStatusList)
                    {
                        byte[] buff = master.Read((byte)item.SlaveId, item.Address, item.IsBaseOne);
                        bool flag = buff[0] == 0x01;
                        item.Data = flag;
                    }
                }

                if (InputCoilList.Count > 8)
                {
                    OptimizeHandle<bool>(InputCoilList, FunctionType.RInputCoil);
                }
                else
                {
                    foreach (var item in CoilStatusList)
                    {
                        byte[] buff = master.Read((byte)item.SlaveId, item.Address, item.IsBaseOne);
                        bool flag = buff[0] == 0x01;
                        item.Data = flag;
                    }
                }

                if (InputRegisterList.Count > 8)
                {
                    OptimizeHandle<short>(InputRegisterList.Where(m => m.DataType == typeof(short).Name).ToList(), FunctionType.RInputRegister);
                    OptimizeHandle<ushort>(InputRegisterList.Where(m => m.DataType == typeof(ushort).Name).ToList(), FunctionType.RInputRegister);
                    OptimizeHandle<int>(InputRegisterList.Where(m => m.DataType == typeof(int).Name).ToList(), FunctionType.RInputRegister);
                    OptimizeHandle<float>(InputRegisterList.Where(m => m.DataType == typeof(float).Name).ToList(), FunctionType.RInputRegister);
                    OptimizeHandle<long>(InputRegisterList.Where(m => m.DataType == typeof(long).Name).ToList(), FunctionType.RInputRegister);
                }
                else
                {
                    foreach (var item in InputRegisterList)
                    {
                        byte[] buff = master.Read((byte)item.SlaveId, item.Address, item.IsBaseOne);
                        MethodInfo method = typeof(ModbusMaster).GetMethod("GetData", BindingFlags.Static | BindingFlags.Public).MakeGenericMethod(Type.GetType(item.DataType));
                        object? val = method.Invoke(null, new object[] { buff.ToList(), item.EndianType });
                        dynamic IdxVal = val;
                        item.Data = IdxVal[0];
                    }
                }

                if (HoldRegisterList.Count > 8)
                {
                    OptimizeHandle<short>(HoldRegisterList.Where(m => m.DataType == typeof(short).Name).ToList(), FunctionType.RInputRegister);
                    OptimizeHandle<ushort>(HoldRegisterList.Where(m => m.DataType == typeof(ushort).Name).ToList(), FunctionType.RInputRegister);
                    OptimizeHandle<int>(HoldRegisterList.Where(m => m.DataType == typeof(int).Name).ToList(), FunctionType.RInputRegister);
                    OptimizeHandle<float>(HoldRegisterList.Where(m => m.DataType == typeof(float).Name).ToList(), FunctionType.RInputRegister);
                    OptimizeHandle<long>(HoldRegisterList.Where(m => m.DataType == typeof(long).Name).ToList(), FunctionType.RInputRegister);
                }
                else
                {
                    foreach (var item in HoldRegisterList)
                    {
                        byte[] buff = master.Read((byte)item.SlaveId, item.Address, item.IsBaseOne);
                        MethodInfo method = typeof(ModbusMaster).GetMethod("GetData", BindingFlags.Static | BindingFlags.Public).MakeGenericMethod(Type.GetType(item.DataType));
                        object? val = method.Invoke(null, new object[] { buff.ToList(), item.EndianType });
                        dynamic IdxVal = val;
                        item.Data = IdxVal[0];
                    }
                }
            }
            else
            {
                foreach (var point in ModbusPoints)
                {
                    byte[] buff = master.Read((byte)SlaveId, point.Address, point.IsBaseOne, LogCallback);
                    //ModbusMaster.GetData<T>(buff.ToList(),point.EndianType);
                    MethodInfo method = typeof(ModbusMaster).GetMethod("GetData", BindingFlags.Static | BindingFlags.Public).MakeGenericMethod(Type.GetType(point.DataType));
                    object? valList = method.Invoke(null, new object[] { buff.ToList(), point.EndianType });

                    if (valList is IEnumerable enumerable)
                    {
                        point.Data = enumerable.Cast<object>().FirstOrDefault();
                    }
                }
            }
        }

        private void LogCallback(object obj)
        {
            LogMessage? message = obj as LogMessage;
            byte[] byteArr = message.Data;
            int status = byteArr[1] > 0x80 ? 1 : 0;
            string logStr = string.Join(' ', byteArr.Select(b => b.ToString("X2")).ToArray());

            Application.Current.Dispatcher.Invoke(() =>
            {
                ModbusLogList.Add(new Data_ModbusLog()
                {
                    SlaveId = byteArr[0],
                    ComPort = PortName,
                    Content = logStr,
                    MsgType = message.MsgType,
                    Status = status,
                    StatusMsg = message.ErrorMsg
                });
                if (ModbusLogList.Count > 64)
                    ModbusLogList.RemoveAt(0);
            });
        }

        /// <summary>
        /// 存在缺陷，无法考虑到 同一个存储区不同的数据类型请求的情况
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="PointList"></param>
        /// <param name="FuncType"></param>
        private void OptimizeHandle_pass<T>(List<ModbusPoint> PointList, FunctionType FuncType)
        {
            // slaveId, List<address>
            Dictionary<int, List<ushort>> OptimizedMap = new Dictionary<int, List<ushort>>();
            PointList.ForEach(c =>
            {
                if (!OptimizedMap.ContainsKey(c.SlaveId))
                {
                    OptimizedMap.Add(c.SlaveId, new List<ushort>());
                }
                OptimizedMap[c.SlaveId].Add(c.StartAddr);
            });

            // 算法概述：分组，间隔大于8分为一组
            // 3,5,7,8  16,18,19,20,21,23
            List<RangeQueryCondition> rangeCondition = new List<RangeQueryCondition>();
            foreach (var key in OptimizedMap.Keys)
            {
                List<ushort> list = OptimizedMap[key];
                list.Sort();    // 默认从小到大排序
                RangeQueryCondition condition = null;
                for (int i = 0; i < list.Count; i++)
                {
                    if (i == 0)
                    {
                        condition = new RangeQueryCondition();
                        condition.SlaveId = (byte)key;
                        condition.FuncType = FuncType;
                        condition.Address = list[0];
                        condition.Offset++;
                        condition.Count++;
                        rangeCondition.Add(condition);
                        continue;
                    }
                    // 判断当前地址 与 前一个地址的偏移量是否大于 8
                    if ((list[i] - 8) >= list[i - 1])
                    {
                        condition = new RangeQueryCondition();
                        condition.SlaveId = (byte)key;
                        condition.FuncType = FuncType;
                        condition.Address = list[i];
                        condition.Offset++;
                        condition.Count++;
                        rangeCondition.Add(condition);
                        continue;
                    }

                    condition.Offset = (ushort)((list[i] - condition.Address) + 1);
                    condition.Count++;
                }
            }

            int offset = 0;
            foreach (var condition in rangeCondition)
            {
                byte[] resp_bytes = master.Read(condition.SlaveId, condition.FuncType, condition.Address, condition.Offset, LogCallback);
                List<T> dataList = ModbusMaster.GetData<T>(resp_bytes.ToList());
                // 注意这里可能会出现好几个分组访问的都是一个从站，但是一次性读取的数量太多的情况，这里每次只读取每个范围查询内的数据
                List<ModbusPoint> ModbusPoints = PointList.Where(c => c.SlaveId == condition.SlaveId).Skip(offset).Take(condition.Count).ToList();
                offset += condition.Count;
                for (int i = 0; i < ModbusPoints.Count; i++)
                {
                    int idx = ModbusPoints[i].StartAddr - condition.Address;
                    ModbusPoints[i].Data = dataList[idx];
                }
            }
        }

        private void OptimizeHandle<T>(List<ModbusPoint> PointList, FunctionType FuncType)
        {
            if(PointList.Count == 0) return;
            // slaveId, List<ModbusPoint>
            Dictionary<int, List<ModbusPoint>> OptimizedMap = new Dictionary<int, List<ModbusPoint>>();
            PointList.ForEach(c =>
            {
                if (!OptimizedMap.ContainsKey(c.SlaveId))
                {
                    OptimizedMap.Add(c.SlaveId, new List<ModbusPoint>());
                }
                OptimizedMap[c.SlaveId].Add(c);
            });

            // 算法概述：分组，间隔大于8分为一组
            // 3,5,7,8  16,18,19,20,21,23
            List<RangeQueryCondition> rangeCondition = new List<RangeQueryCondition>();
            foreach (var key in OptimizedMap.Keys)
            {
                List<ModbusPoint> list = OptimizedMap[key];
                list.Sort((a, b) => a.StartAddr.CompareTo(b.StartAddr));

                RangeQueryCondition condition = null;
                for (int i = 0; i < list.Count; i++)
                {
                    if (i == 0)
                    {
                        condition = new RangeQueryCondition();
                        condition.SlaveId = (byte)key;
                        condition.FuncType = FuncType;
                        condition.Address = list[0].StartAddr;
                        condition.Count++;
                        condition.Offset++;
                        condition.EndianType = list[0].EndianType;
                        rangeCondition.Add(condition);
                        continue;
                    }
                    // 判断当前地址 与 前一个地址的偏移量是否大于 8
                    if ((list[i].StartAddr - 8) >= list[i - 1].StartAddr)
                    {
                        condition = new RangeQueryCondition();
                        condition.SlaveId = (byte)key;
                        condition.FuncType = FuncType;
                        condition.Address = list[i].StartAddr;
                        condition.Count++;
                        condition.Offset++;
                        condition.EndianType = list[i].EndianType;
                        rangeCondition.Add(condition);
                        continue;
                    }

                    // 计算一个分组中最后一个与第一个之间的位置偏移量
                    switch(list[i].DataType)
                    {
                        case "Single":
                        case "Int32":
                            condition.Offset = (ushort)((list[i].StartAddr - condition.Address) + 2);
                            break;
                        case "Int64":
                            condition.Offset = (ushort)((list[i].StartAddr - condition.Address) + 4);
                            break;
                        default:
                            condition.Offset = (ushort)((list[i].StartAddr - condition.Address) + 1);
                            break;
                    }
                    
                    condition.Count++;
                }
            }

            int offset = 0;
            foreach (var condition in rangeCondition)
            {
                byte[] resp_bytes = master.Read(condition.SlaveId, condition.FuncType, condition.Address, condition.Offset, LogCallback);
                List<T> dataList = ModbusMaster.GetData<T>(resp_bytes.ToList());

                // 注意这里可能会出现好几个分组访问的都是一个从站，但是一次性读取的数量太多的情况，这里每次只读取每个范围查询内的数据
                List<ModbusPoint> ModbusPoints = PointList.Where(c => c.SlaveId == condition.SlaveId).Skip(offset).Take(condition.Count).ToList();
                offset += condition.Count;
                int size = 1;
                if (typeof(T).Name == "Single" || typeof(T).Name == "Int32")
                {
                    size = 2;
                }
                else if (typeof(T).Name == "Int64")
                {
                    size = 4;
                }
                for (int i = 0; i < ModbusPoints.Count; i++)
                {
                    int idx = (ModbusPoints[i].StartAddr - condition.Address) / size;    // offset = 8 - 0 / size
                    ModbusPoints[i].Data = dataList[idx];
                }
            }
        }
    }

    class RangeQueryCondition
    {
        public byte SlaveId { get; set; }
        public FunctionType FuncType { get; set; }
        public ushort Address { get; set; }
        /// <summary>
        /// 从起始地址开始偏移多少个点位
        /// </summary>
        public ushort Offset { get; set; }
        /// <summary>
        /// 实际范围内的数据个数
        /// </summary>
        public ushort Count { get; set; }
        public EndianType EndianType { get; set; }
    }
}
